package com.gjzhao.fmmall.controller;

import com.gjzhao.fmmall.entity.Product;
import com.gjzhao.fmmall.entity.ProductComments;
import com.gjzhao.fmmall.service.ProductCommentsService;
import com.gjzhao.fmmall.service.ProductService;
import com.gjzhao.fmmall.vo.RespResultVO;
import com.gjzhao.fmmall.vo.ResponseResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description: 商品管理 Controller
 * @Author: gjzhao
 * @Date Created in 2022-01-02 1:55 下午
 */
@RestController
@RequestMapping("/product")
@CrossOrigin
@Api(value = "商品信息接口", tags = "商品管理")
public class ProductController extends BaseController {

    @Autowired
    private ProductService productService;
    @Autowired
    private ProductCommentsService productCommentsService;


    /**
     * RESTful风格的请求，需要配合 @PathVariable 注解一起使用
     *
     * @param productId
     * @return
     */
    @GetMapping("/detailInfo/{productId}")
    @ApiOperation(value = "商品基本信息查询")
    @ApiImplicitParam(dataType = "string", name = "productId", value = "商品id", required = true)
    public ResponseResultVO listProductBasicInfo(@PathVariable String productId) {
        ResponseResultVO resultVO = productService.listProductBasicInfo(productId);
        return resultVO;
    }

    /**
     * 接口作用：根据商品id从后台查询商品详情信息
     * 业务流程分析：
     *      - 1.前端拿着商品id，向后台发送请求查询商品详情信息
     *      - 2.后台根据商品id查询商品信息(商品基本信息/商品主图信息/商品sku信息)
     *          - 2.1 从redis数据库查询是否存在信息
     *              - 2.1.1 如果存在，直接返回查询到的数据
     *              - 2.1.2 如果不存在，先从数据库查询到商品信息，返回商品信息给前端，同时缓存到redis
     * @param productId
     * @return
     */
    @GetMapping("/detailInfoByRedis/{productId}")
    @ApiOperation(value = "商品基本信息查询(使用redis缓存数据)")
    @ApiImplicitParam(dataType = "string", name = "productId", value = "商品id", required = true)
    public RespResultVO detailInfoByRedis(@PathVariable String productId) {
        RespResultVO resultVO = productService.listProductBasicInfoByRedis(productId);
        return resultVO;
    }


    @GetMapping("/detailParams/{productId}")
    @ApiOperation(value = "商品参数信息查询")
    @ApiImplicitParam(dataType = "string", name = "productId", value = "商品id", required = true)
    public ResponseResultVO listProductParams(@PathVariable String productId) {
        ResponseResultVO resultVO = productService.listProductParams(productId);
        return resultVO;
    }

    @GetMapping("/detailComments/{productId}")
    @ApiOperation(value = "商品评价信息查询")
    public ResponseResultVO listProductComments(@PathVariable String productId) {
        ResponseResultVO resultVO = productCommentsService.listProductComments(productId);
        return resultVO;
    }

    /**
     * 接口作用：根据商品id，查询该商品的评价信息，进行分页(
     *  todo 1：添加评价类型查询，可根据好评/中评/差评进行分页查询 (已做)
     *  todo 2：展示评价用户的名字时需要进行脱敏操作
     * )
     * 业务流程分析：
     *   - 1.在商品详情页面，点击"商品评价"
     *   - 2.调用该接口，根据商品id查询商品评价(同时需要关联用户表查询每条评价是哪个用户的)
     * @param productId
     * @param pageNum
     * @param limit
     * @return
     */
    @GetMapping("/detailCommentsPage/{productId}")
    @ApiOperation(value = "商品评价信息查询(分页查询)")
    @ApiImplicitParams({
        @ApiImplicitParam(dataType = "int", name = "commType", value = "评价类型", required = false),
        @ApiImplicitParam(dataType = "int", name = "pageNum", value = "当前页数", required = true),
        @ApiImplicitParam(dataType = "int", name = "limit", value = "每页条数", required = true)
    })
    public ResponseResultVO listProductCommentsPage(@PathVariable String productId,
                                                    @RequestParam("commType") int commType,
                                                    @RequestParam("pageNum") int pageNum,
                                                    @RequestParam("limit") int limit
    ) {
        ResponseResultVO resultVO = productCommentsService.listProductCommentsPage(productId, commType, pageNum, limit);
        return resultVO;
    }

    /**
     * 接口作用：根据商品id，查询该商品的评价情况(总评论条数/好评数/中评数/差评数/好评率)
     * 业务流程分析：
     *   - 1.用户在商品详情页，点击"商品评价"
     *   - 2.调用该接口，返回商品评论情况
     * @param productId
     * @return
     */
    @GetMapping("/detailCommentsCount/{productId}")
    @ApiOperation(value = "统计商品评价信息(总评论/好评/中评/差评)")
    public ResponseResultVO listProductCommentsCount(@PathVariable String productId) {
        ResponseResultVO resultVO = productCommentsService.listProductCommentsCount(productId);
        return resultVO;
    }


    /**
     * 接口作用：根据商品所属类别(这里细分的是三级分类)查询商品列表信息
     * 业务流程分析：
     *      - 1.在网站首页，点击分类，选择三级分类，比如:电子设备 -> 手机 -> 苹果
     *      - 2.根据商品类别，调用该接口查询该类别下的所有商品信息(可加上限制条件，比如：该商品销量最高的套餐/价格最低的套餐)，封装分页信息
     *      - 3.返回给前端进行分页展示
     * @param categoryId
     * @param pageNum
     * @param limit
     * @return
     */
    @GetMapping("/listProductsPage/{categoryId}")
    @ApiOperation(value = "根据三级分类查询所有商品(分页查询)")
    @ApiImplicitParams({
        @ApiImplicitParam(dataType = "int", name = "pageNum", value = "当前页数", required = true),
        @ApiImplicitParam(dataType = "int", name = "limit", value = "每页条数", required = true)
    })
    public ResponseResultVO listProductsPage(@PathVariable String categoryId,
                                             @RequestParam("pageNum") int pageNum,
                                             @RequestParam("limit") int limit
    ) {
        ResponseResultVO resultVO = productService.listProductByCategory(categoryId, pageNum, limit);
        return resultVO;
    }


    /**
     * 接口作用：查询当前分类id下所有的商品品牌
     * 业务流程分析：
     *      - 1.用户点击三级分类进入到商品列表页面，需要展示当前这些商品涉及到哪些品牌
     *      - 2.根据分类id，调用该接口，查询当前分类下的所有商品id，根据商品id去商品参数表查找品牌名字
     *      - 3.返回商品品牌名字列表给前端
     * @param categoryId
     * @return
     */
    @GetMapping("/listBrands/{categoryId}")
    @ApiOperation(value = "根据类别ID查询当前类别下的所有商品品牌")
    public ResponseResultVO listBrands(@PathVariable Integer categoryId) {
        ResponseResultVO resultVO = productService.listBrandsByCategory(categoryId);
        return resultVO;
    }


    /**
     * //todo 后面考虑看能不能使用es进行替代搜索功能(已使用)
     * 接口作用：根据关键词查询相关商品，进行列表分页查询
     * 业务流程分析：
     *      - 1.用户在搜索输入框输入"关键词"
     *      - 2.根据关键词模糊匹配查询商品信息
     *      - 3.将所有相关的商品信息分页方式返回给前端
     * @param keyword
     * @param pageNum
     * @param limit
     * @return
     */
    @GetMapping("/searchProductsPage/{keyword}")
    @ApiOperation(value = "根据关键词搜索商品信息(模糊匹配方式)")
    @ApiImplicitParams({
        @ApiImplicitParam(dataType = "int", name = "pageNum", value = "当前页数", required = true),
        @ApiImplicitParam(dataType = "int", name = "limit", value = "每页条数", required = true)
    })
    public ResponseResultVO searchProductsPage(@PathVariable String keyword,
                                               @RequestParam("pageNum") int pageNum,
                                               @RequestParam("limit") int limit
    ) {
        ResponseResultVO resultVO = productService.searchProductByKeyword(keyword, pageNum, limit);
        return resultVO;
    }

    /**
     * 接口作用：根据用户输入的关键词去es中匹配结果，找到响应文档信息
     * 业务流程分析：
     *  - 1.用户在搜索栏输入商品关键词信息，调用该接口
     *  - 2.根据该关键词去es中查询文档信息
     *  - 3.根据响应结果，封装高亮数据返回给前端
     *
     *
     * @param keyword
     * @param pageNum
     * @param limit
     * @return
     */
    @GetMapping("/searchProductsPageByElasticsearch/{keyword}")
    @ApiOperation(value = "根据关键词搜索商品信息[使用elasticsearch实现]")
    @ApiImplicitParams({
        @ApiImplicitParam(dataType = "int", name = "pageNum", value = "当前页数", required = true),
        @ApiImplicitParam(dataType = "int", name = "limit", value = "每页条数", required = true)
    })
    public RespResultVO searchProductsPageByElasticsearch(@PathVariable String keyword,
                                               @RequestParam("pageNum") int pageNum,
                                               @RequestParam("limit") int limit
    ) {
        RespResultVO respResultVO = productService.searchProductByKeywordByEs(keyword, pageNum, limit);
        return respResultVO;
    }


    /**
     * 接口作用：在引入es后且上线前,将引入es之前所有数据库的商品信息添加到es的指定索引中
     * 流程分析：
     * - 1.引入es之前，搜索商品时，在后台sql中使用like进行模糊匹配，但是当数据量达到百万时，这样的查询速度非常慢，引入es解决该问题
     * - 2.引入es之后，用户搜索商品时，不需要从数据库进行查询，直接从es中进行匹配
     * - 3.如何保证es数据与数据库数据一致？
     *      - 3.1 引入es之前，此时数据库如果已经存在商品信息，需要将商品信息手动导入到es中
     *      - 3.2 引入es之后，每次添加商品时，除了需要添加到数据库中，还需要同步到es中
     *                      每次下架商品时，除了需要删除输出数据库中数据，还需要删除es中数据
     *
     * @return
     */
    @GetMapping("/queryAllProductsInitIntoEs")
    @ApiOperation(value = "查询所有商品信息导入到elasticsearch(在es上线前操作)")
    public RespResultVO queryAllProductInitIntoEs() {
        RespResultVO respResultVO = productService.initProductsIntoEs();
        return respResultVO;
    }



    /**
     * 接口作用：根据搜索的商品关键词，查找涉及的所有品牌名字
     *      - 1.用户在搜索输入框输入"关键词"
     *      - 2.根据关键词查询所有相关的商品id，再从商品参数表中查找这些商品id中的所有品牌(去重)
     * @param keyword
     * @return
     */
    @GetMapping("/searchBrandsByKeyword/{keyword}")
    @ApiOperation(value = "根据关键词查询出来的商品的所有品牌信息")
    public ResponseResultVO listBrandsByKeyword(@PathVariable String keyword) {
        ResponseResultVO resultVO = productService.listBrandsByKeyword(keyword);
        return resultVO;
    }


    @PostMapping("/add")
    @ApiOperation(value = "添加商品评价")
    public ResponseResultVO listProductBasicInfo(@RequestHeader("token") String token,
                                                 @RequestBody ProductComments productComment) {

        ResponseResultVO resultVO = productCommentsService.insertProductComments(productComment);
        return resultVO;
    }


    /**
     * 接口作用：添加商品 (todo 现在写的是前台逻辑部分，这里只写es部分)
     * 业务流程分析：
     *      - 1.在后台管理中，商家需要进行添加商品操作，填入商品信息
     *      - 2.调用该接口
     *          - 2.1 商品信息存入数据库
     *          - 2.2 由于引入了es，同时需要将商品信息存入到es中
     * @param token
     * @param product
     * @return
     */
    @PostMapping("/addProduct")
    @ApiOperation(value = "添加商品")
    public RespResultVO addProduct(@RequestHeader("token") String token,
                                   @RequestBody Product product) {

        RespResultVO resultVO = productService.insertProduct(product);
        return resultVO;
    }

    /**
     * 接口作用：删除商品 (todo 现在写的是前台逻辑部分，这里只写es部分)
     * 业务流程分析：
     *      - 1.在后台管理中，商家需要进行删除商品操作，选择需要删除的商品
     *      - 2.调用该接口
     *          - 2.1 从数据库中删除该条商品信息
     *          - 2.2 由于引入了es，需要将es中的商品信息同步删除
     * @param token
     * @param productId
     * @return
     */
    @GetMapping("/deleteProduct")
    @ApiOperation(value = "删除商品")
    @ApiImplicitParam(dataType = "string", name = "productId", value = "商品id", required = true)
    public RespResultVO deleteProduct(@RequestHeader("token") String token,
                                      @RequestParam("productId") String productId) {

        RespResultVO resultVO = productService.deleteProduct(productId);
        return resultVO;
    }

}
